from bs4 import BeautifulSoup  # 网页解析，数据获取
import os
import re  # 正则表达式，文字匹配
import urllib.request, urllib.error, urllib.parse  # 指定url，获取网页数据
import sqlite3
import time

# 影评跳转链接匹配
findLink = re.compile(r'<h2><a href="(.*?)">.*</a></h2>', re.S)  # 指定规则，创建正则表达式对象
# 影评标题匹配
findTitle = re.compile(r'<span property="v:summary">(.*?)</span>', re.S)


# re.S防止换行符影响我们提取
# 根据指定url获取网页html源代码
def getHtml(baseurl):
    head = {  # 模拟浏览器身份头向对方发送消息
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.46 (KHTML, like Gecko) Chrome/83.0.4133.126 Safari/537.46"
        # cookie信息如果你真想以一个登陆用户身份访问网页的话就写上
    }
    # 向豆瓣服务器发送请求
    req = urllib.request.Request(url=baseurl, headers=head)
    html = ""
    # 为了在受到反爬系统反制时及时收手，采用try方式，如果访问失败直接返回空字符串协助main函数跳出循环
    try:
        response = urllib.request.urlopen(req)
        html = response.read().decode("utf-8")
    except urllib.error.URLError as e:
        if hasattr(e, "reason"):
            print(e.reason)
        else:
            print("访问发生了其他错误")
        html = ""
    return html


def saveData(review_text):
    TENET = sqlite3.connect("TENET.db")
    c = TENET.cursor()  # 游标
    print("写入影评:" + str(review_text[0]))
    c.execute("insert into Review values(?,?,?)", (review_text[0] + 1, review_text[1], review_text[2]))
    TENET.commit()  # 提交数据库操作
    TENET.close()  # 关闭数据库


def main():
    if os.path.exists("TENET.db"):
        os.remove("TENET.db")
    TENET = sqlite3.connect("TENET.db")
    print("数据库连接完成")
    c = TENET.cursor()  # 游标
    sql = '''
        create table Review
        (
            id int primary key,
            title text not null,
            review text nut null
        );
    '''
    c.execute(sql)
    TENET.commit()  # 提交数据库操作
    TENET.close()  # 关闭数据库

    baseurl = "https://movie.douban.com/subject/30444960/reviews?start="
    i = 0
    j = 0
    # 1000+影评运行时间会在1h左右，也许就会产生新一整页影评。所以不用for循环，直接上while
    running = True
    # 获取《信条》影评网页源代码信息
    while running:
        # 以20为单位相当于在跳转到“第几页”
        html = getHtml(baseurl + str(i * 20))
        if html != "":
            # 逐一解析影评页面每一个标签
            soup = BeautifulSoup(html, 'html.parser')
            # 用于记录所有具体影评链接
            a_href_data = []
            for item in soup.find_all('div', class_="main-bd"):
                item = str(item)
                link = re.findall(findLink, item)[0]
                a_href_data.append(link)

            # 接下来开始访问所有影评网页
            for url in a_href_data:
                # 我太菜了，反反爬只能用此下等卑微的措施
                time.sleep(4)
                # 获取单个影评网页源代码信息
                html = getHtml(url)
                # 逐一解析一个影评的每一个标签
                soup = BeautifulSoup(html, 'html.parser')
                # 标题
                title = ""
                for item in soup.find_all('h1'):
                    item = str(item)
                    title = re.findall(findTitle, item)[0]
                    title = re.sub("\n", "", title)
                # 找内容所在的盒子
                for item in soup.find_all('div', id="link-report"):
                    item = str(item)
                    # 影评内容
                    text = ""
                    # 一个影评盒子内的p标签们全部由soup处理
                    soup_content = BeautifulSoup(item, 'html.parser')
                    # 针对所有p标签内容
                    for item_content in soup_content.find_all('p'):
                        item_content = str(item_content)
                        # 针对span标签的额外处理
                        item_content = re.sub(r'<span style=".*">', "", item_content)  # 删除span
                        item_content = re.sub('</span>', " ", item_content)  # 删除span
                        item_content = re.sub(r'<p.*">', "", item_content)  # 删除有样式的p报签
                        item_content = re.sub('<p>', "", item_content)  # 删除没样式的p标签
                        item_content = re.sub('</p>', " ", item_content)  # 删除p标签
                        # 写影评
                        if item_content != "":
                            text += item_content + "\n"

                print(title + " 已获取完成")
                # 存入数据库
                saveData([j, title, text])
                j += 1
            i += 1
        else:
            running = False
            # os.system("pause")


if __name__ == "__main__":
    main()
